// Copyright (c) 2009 Daniel Waterworth.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

#include <map>
#include <list>

#include "securityexception.h"

using namespace std;

// memory checking
// char * because you can increment char *s one byte at a time
map<char *, size_t> alloc;

void alloc_log(char *begin, size_t size) {
  alloc.insert(pair<char *, size_t>(begin, size));
}

void dealloc_log(char *begin) {
  alloc.erase(begin);
}

static bool check(char *begin, size_t size, map<char *, size_t>::iterator iter) {
  return begin >= iter->first && begin+size <= iter->first+iter->second;
}

void alloc_check(void *begin, size_t size) {
  map<char *, size_t>::iterator iter = alloc.lower_bound((char*)begin);
  if (iter != alloc.end()) {
    if (check((char*)begin, size, iter) == true)
      return;
  }
  --iter;
  if (iter != alloc.end()) {
    if (check((char*)begin, size, iter) == true)
      return;
  }
  throw security_exception;
}

void *secure_malloc(size_t size) {
  void *ptr = malloc(size);
  alloc_log((char*)ptr, size);
  return ptr;
}

void secure_free(void *ptr) {
  alloc_check((char*)ptr, 1);
  dealloc_log((char*)ptr);
  free(ptr);
}

void bounds_check(void *ptr, size_t size, void *check, size_t datasize) {
  printf("bounds_check called: %x %d %x %i\n", ptr, size, check, datasize);
  if (!(check >= (unsigned char*)ptr && (unsigned char*)check+datasize <= (unsigned char*)ptr+size)) {
    printf("exception thrown - bounds_check\n");
    throw security_exception;
  }
}

// it may be possible to remove all of the proceeding code.

/*typedef pair<char *, char *> stackframe;
// represents the begining of the stack frame and one past the end.

list<stackframe> stack;

static bool __attribute__((noinline)) StackCmp(volatile void *ptr) {
  volatile int a;
  return (void *)&a > ptr;
}

bool FindStackDirection() {
  volatile int a;
  return StackCmp((void *)&a);
}

bool direction = FindStackDirection();

void push_val(size_t size) {
  if (direction)
    stack.back().second += size;
  else
    stack.back().second -= size;
}

void pop_val(size_t size) {
  if (!direction)
    stack.back().second += size;
  else
    stack.back().second -= size;
}

void push_frame(char *ptr) {
  stack.push_back(stackframe(ptr, ptr));
}

void pop_frame() {
  stack.pop_back();
}

bool stack_check(char *begin, size_t size) {
  if (stack.empty())
    return false;
  
  if (direction) {
    // quickly elimemate ptrs that are definately not on the stack.
    if (begin >= stack.front().first && begin+size <= stack.back().second) {
      for (list<stackframe>::iterator iter = stack.begin(); iter != stack.end(); ++iter) {
        //if (iter->first <= 
      }
    }
  } else {
  
  }
  
  return false;
}

bool mem_check(char *begin, size_t size) {
  if (stack_check(begin, size) == true)
    return true;
  if (alloc_check(begin, size) == true)
    return true;
  return false;
}*/
